kernel).
Add index macros (XS_WATCH_*) for accessing the array to allow for future
expansion.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
return buffer;
}
-char **xenbus_directory(const char *dir, const char *node, unsigned int *num)
+static char **split(char *strings, unsigned int len, unsigned int *num)
{
- char *strings, *p, **ret;
- unsigned int len;
-
- strings = xs_single(XS_DIRECTORY, join(dir, node), &len);
- if (IS_ERR(strings))
- return (char **)strings;
+ char *p, **ret;
/* Count the strings. */
*num = count_strings(strings, len);
strings = (char *)&ret[*num];
for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
ret[(*num)++] = p;
+
return ret;
}
+
+char **xenbus_directory(const char *dir, const char *node, unsigned int *num)
+{
+ char *strings;
+ unsigned int len;
+
+ strings = xs_single(XS_DIRECTORY, join(dir, node), &len);
+ if (IS_ERR(strings))
+ return (char **)strings;
+
+ return split(strings, len, num);
+}
EXPORT_SYMBOL(xenbus_directory);
/* Check if a path exists. Return 1 if it does. */
return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
}
-static char *xs_read_watch(char **token)
+static char **xs_read_watch(unsigned int *num)
{
enum xsd_sockmsg_type type;
- char *ret;
+ char *strings;
+ unsigned int len;
- ret = read_reply(&type, NULL);
- if (IS_ERR(ret))
- return ret;
+ strings = read_reply(&type, &len);
+ if (IS_ERR(strings))
+ return (char **)strings;
BUG_ON(type != XS_WATCH_EVENT);
- *token = ret + strlen(ret) + 1;
- return ret;
+
+ return split(strings, len, num);
}
static int xs_acknowledge_watch(const char *token)
static int watch_thread(void *unused)
{
for (;;) {
- char *token;
- char *node = NULL;
+ char **vec = NULL;
+ unsigned int num;
wait_event(xb_waitq, xs_input_avail());
*/
down(&xenbus_lock);
if (xs_input_avail())
- node = xs_read_watch(&token);
+ vec = xs_read_watch(&num);
- if (node && !IS_ERR(node)) {
+ if (vec && !IS_ERR(vec)) {
struct xenbus_watch *w;
int err;
- err = xs_acknowledge_watch(token);
+ err = xs_acknowledge_watch(vec[XS_WATCH_TOKEN]);
if (err)
printk(KERN_WARNING "XENBUS ack %s fail %i\n",
- node, err);
- w = find_watch(token);
+ vec[XS_WATCH_TOKEN], err);
+ w = find_watch(vec[XS_WATCH_TOKEN]);
BUG_ON(!w);
- w->callback(w, node);
- kfree(node);
- } else if (node)
+ w->callback(w, vec[XS_WATCH_PATH]);
+ kfree(vec);
+ } else if (vec)
printk(KERN_WARNING "XENBUS xs_read_watch: %li\n",
- PTR_ERR(node));
+ PTR_ERR(vec));
up(&xenbus_lock);
}
}
char *node = NULL;
struct xenbus_watch *w;
int er;
+ unsigned int num;
- res = xs_read_watch(h);
+ res = xs_read_watch(h, &num);
if (res == NULL)
return -EAGAIN; /* in O_NONBLOCK, read_watch returns 0... */
- node = res[0];
- token = res[1];
+ node = res[XS_WATCH_PATH];
+ token = res[XS_WATCH_TOKEN];
er = xs_acknowledge_watch(h, token);
if (er == 0)
char **vec;
int domid;
struct domain *dom;
+ unsigned int num;
- vec = xs_read_watch(xs);
+ vec = xs_read_watch(xs, &num);
if (!vec)
return;
- if (!strcmp(vec[1], "domlist"))
+ if (!strcmp(vec[XS_WATCH_TOKEN], "domlist"))
enum_domains();
- else if (sscanf(vec[1], "dom%u", &domid) == 1) {
+ else if (sscanf(vec[XS_WATCH_TOKEN], "dom%u", &domid) == 1) {
dom = lookup_domain(domid);
if (dom->is_dead == false)
domain_create_ring(dom);
char **xsval = NULL;
PyObject *token;
int i;
+ unsigned int num;
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
goto exit;
Py_BEGIN_ALLOW_THREADS
- xsval = xs_read_watch(xh);
+ xsval = xs_read_watch(xh, &num);
Py_END_ALLOW_THREADS
if (!xsval) {
PyErr_SetFromErrno(PyExc_RuntimeError);
goto exit;
}
- if (sscanf(xsval[1], "%li", (unsigned long *)&token) != 1) {
+ if (sscanf(xsval[XS_WATCH_TOKEN], "%li", (unsigned long *)&token) != 1) {
PyErr_SetString(PyExc_RuntimeError, "invalid token");
goto exit;
}
goto exit;
}
/* Create tuple (path, token). */
- val = Py_BuildValue("(sO)", xsval[0], token);
+ val = Py_BuildValue("(sO)", xsval[XS_WATCH_PATH], token);
exit:
if (xsval)
free(xsval);
/* Generally followed by nul-terminated string(s). */
};
+/* FIXME we shouldn't have to declare this in two places, what's the right
+ way to share things between xenstored.h and xs.h? */
+enum xs_watch_type
+{
+ XS_WATCH_PATH = 0,
+ XS_WATCH_TOKEN,
+};
+
#endif /* _XENSTORED_H */
* Returns array of two pointers: path and token, or NULL.
* Call free() after use.
*/
-char **xs_read_watch(struct xs_handle *h)
+char **xs_read_watch(struct xs_handle *h, unsigned int *num)
{
struct xsd_sockmsg msg;
char **ret;
+ char *strings;
+ unsigned int num_strings, i;
if (!read_all(h->fd, &msg, sizeof(msg)))
return NULL;
assert(msg.type == XS_WATCH_EVENT);
- ret = malloc(sizeof(char *)*2 + msg.len);
- if (!ret)
+ strings = malloc(msg.len);
+ if (!strings)
return NULL;
- ret[0] = (char *)(ret + 2);
- if (!read_all(h->fd, ret[0], msg.len)) {
- free_no_errno(ret);
+ if (!read_all(h->fd, strings, msg.len)) {
+ free_no_errno(strings);
return NULL;
}
- ret[1] = ret[0] + strlen(ret[0]) + 1;
+
+ num_strings = xs_count_strings(strings, msg.len);
+
+ ret = malloc(sizeof(char*) * num_strings + msg.len);
+ if (!ret) {
+ free_no_errno(strings);
+ return NULL;
+ }
+
+ ret[0] = (char *)(ret + num_strings);
+ memcpy(ret[0], strings, msg.len);
+ free(strings);
+
+ for (i = 1; i < num_strings; i++) {
+ ret[i] = ret[i - 1] + strlen(ret[i - 1]) + 1;
+ }
+
+ *num = num_strings;
+
return ret;
}
struct xs_handle;
+/* FIXME we shouldn't have to declare this in two places, what's the right
+ way to share things between xenstored.h and xs.h? */
+enum xs_watch_type
+{
+ XS_WATCH_PATH = 0,
+ XS_WATCH_TOKEN,
+};
+
/* On failure, these routines set errno. */
/* Connect to the xs daemon.
int xs_fileno(struct xs_handle *h);
/* Find out what node change was on (will block if nothing pending).
- * Returns array of two pointers: path and token, or NULL.
- * Call free() after use.
+ * Returns array containing the path and token. Use XS_WATCH_* to access these
+ * elements. Call free() after use.
*/
-char **xs_read_watch(struct xs_handle *h);
+char **xs_read_watch(struct xs_handle *h, unsigned int *num);
/* Acknowledge watch on node. Watches must be acknowledged before
* any other watches can be read.
/* Convenient for testing... */
if (swallow_event) {
- char **vec = xs_read_watch(handles[handle]);
- if (!vec || !streq(vec[0], node) || !streq(vec[1], token))
+ unsigned int num;
+ char **vec = xs_read_watch(handles[handle], &num);
+ if (!vec ||
+ !streq(vec[XS_WATCH_PATH], node) ||
+ !streq(vec[XS_WATCH_TOKEN], token))
failed(handle);
if (!xs_acknowledge_watch(handles[handle], token))
failed(handle);
struct timeval tv = {.tv_sec = timeout_ms/1000,
.tv_usec = (timeout_ms*1000)%1000000 };
fd_set set;
+ unsigned int num;
if (xs_fileno(handles[handle]) != -2) {
/* Manually select here so we can time out gracefully. */
set_timeout();
}
- vec = xs_read_watch(handles[handle]);
+ vec = xs_read_watch(handles[handle], &num);
if (!vec) {
failed(handle);
return;
}
if (handle)
- output("%i:%s:%s\n", handle, vec[0], vec[1]);
+ output("%i:%s:%s\n", handle,
+ vec[XS_WATCH_PATH], vec[XS_WATCH_TOKEN]);
else
- output("%s:%s\n", vec[0], vec[1]);
+ output("%s:%s\n", vec[XS_WATCH_PATH], vec[XS_WATCH_TOKEN]);
free(vec);
}